#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <mpi.h>

#include "lib.h"

int main(int argc, char **argv){
	int rank, tamanhoNomeComputador;
	char nomeComputador[MPI_MAX_PROCESSOR_NAME];

	/* inicia a sessao MPI */
	MPI_Init(&argc, &argv);

	/* obtem o rank do processo */
	MPI_Comm_rank(MPI_COMM_WORLD, &rank);

	if (rank == 0){
		int nProcessos, cntProcessos, tamanhoArquivo, inicioParticao, fimParticao, nPalindromos, nPalindromosFrases;
		FILE *fp;
		char *buffer;

		/* pega o numero de processos */
		MPI_Comm_size(MPI_COMM_WORLD, &nProcessos);

		/* abre o arquivo de texto */
		fp = fopen("data-t2/shakespe.txt", "r");

		/* verifica se o arquivo foi aberto */
		if(fp == NULL){
			printf("ERRO: Nao foi possivel abrir o arquivo data-t2/shakespe.txt!!!\n");
			exit(1);
		}

		/* calcula o tamanho do arquivo */
		fseek(fp, 0, SEEK_END);
		tamanhoArquivo = ftell(fp);

		/* retorna o ponteiro para o inicio do arquivo */
		fseek(fp, 0, SEEK_SET);
	
		/* aloca o buffer para carregar o arquivo na memoria */
		buffer = (char *)malloc(sizeof(char) * tamanhoArquivo);

		/* carrega o arquivo na memoria */
		fread(buffer, sizeof(char), tamanhoArquivo, fp);

		/* fecha o arquivo */
		fclose(fp);

		/* divide o texto em particoes e envia para os processos */
		inicioParticao = fimParticao = 0;
		for(cntProcessos = 0; cntProcessos < nProcessos - 1; ++cntProcessos){
			/* calcula o fim da particao */
			fimParticao = ((float)tamanhoArquivo / nProcessos) * (cntProcessos + 1);

			/* ajusta o fim da particao para nao dividir uma palavra */
			while(buffer[fimParticao] != '?' && buffer[fimParticao] != '!' && buffer[fimParticao] != '.'){
				++fimParticao;
			}

			/* envia a particao para o processo de destino */
			MPI_Send(&buffer[inicioParticao], 
				fimParticao - inicioParticao, 
				MPI_CHAR, 
				cntProcessos + 1, 
				1, 
				MPI_COMM_WORLD);

			/* calcula o inicio da proxima particao */
			inicioParticao = fimParticao;
		}

		/* processa a particao e retorna o numero de palindromos e de frases que sao palindromos */
		processaParticaoFrases(&buffer[inicioParticao], &nPalindromos, &nPalindromosFrases);

		/* desaloca o buffer */
		free(buffer);

		/* imprime algumas informacoes do processo e o numero de palindromos encontrados na particao */
		MPI_Get_processor_name(nomeComputador, &tamanhoNomeComputador);
		fprintf(stderr, 
			"O computador %s terminou processo %d de %d e encontrou %d palindromos e %d frases que sao palindromos.\n", 
			nomeComputador, 
			rank + 1, 
			nProcessos, 
			nPalindromos,
			nPalindromosFrases);
	}else{
		MPI_Status status;
		char *buffer;
		int nPalindromos, nPalindromosFrases, nProcessos;

		/* tenta alocar o buffer e verifica se foi possivel */
		buffer = (char *)malloc(sizeof(char) * 200000000);
		if(buffer == NULL){
			printf("ERRO: Nao foi possivel criar o buffer!!!\n");

			exit(1);
		}

		/* recebe o particao do texto e a salva no buffer */
		MPI_Recv(buffer, 200000000, MPI_CHAR, 0, 1, MPI_COMM_WORLD, &status);

		/* processa a particao e retorna o numero de palindromos e primos*/
		processaParticaoFrases(buffer, &nPalindromos, &nPalindromosFrases);

		/* desaloca o buffer */
		free(buffer);

		/* imprime algumas informacoes do processo e o numero de palindromos encontrados na particao */
		MPI_Comm_size(MPI_COMM_WORLD, &nProcessos);
		MPI_Get_processor_name(nomeComputador, &tamanhoNomeComputador);
		fprintf(stderr, 
			"O computador %s terminou processo %d de %d e encontrou %d palindromos e %d frases que sao palindromos.\n", 
			nomeComputador, 
			rank + 1, 
			nProcessos, 
			nPalindromos,
			nPalindromosFrases);
	}

	/* finaliza a sessao MPI */
	MPI_Finalize();

	return 0;
}
